import os

import requests
import json
import pytest
import allure
from allure_combine import combine_allure


@allure.epic("商机项目")
@allure.feature("商机平台")
@allure.severity("blocker")
@allure.title("商机平台成功访问用例")
def test_graphql_investor_query():
    """
    测试GraphQL投资者分页查询接口
    """
    # 接口地址
    url = "https://zhfx.founderfu.com:13001/graph-api/graphql"

    # 请求头
    headers = {
        "Authorization": "Bearer fzzqtesttoken",
        "Content-Type": "application/json"
    }

    # GraphQL查询和参数
    payload = {
        "variables": {
            "pageNum": 0,
            "pageSize": 20,
            "filter": {
                "investorIdOrName": "",
                "isRemark": "",
                "mobile": "",
                "addr": "",
                "orderType": "0",
                "holdAgmt": "",
                "minRight": None,
                "maxRight": None,
                "labelIds": []
            }
        },
        "query": """
        query ($pageNum: Int, $pageSize: Int, $filter: InvestorCenterFilter) {
          findStaffCustByPage(pageNum: $pageNum, pageSize: $pageSize, filter: $filter) {
            staffCustData {
              investorId
              investorNam
              level
              boNum
              mobileNo
              futAssets
              subMonthSum
              investorFlag
              custLabels {
                lableId
                lableName
                __typename
              }
              __typename
            }
            pageInfo {
              hasNextPage
              hasPreviousPage
              totalCount
              __typename
            }
            __typename
          }
        }
        """
    }

    try:
        # 发送POST请求
        response = requests.post(url, headers=headers, json=payload)
        response.raise_for_status()

        # 解析响应数据
        response_data = response.json()

        # 断言部分
        # 1. 验证HTTP状态码
        assert response.status_code == 200, f"期望状态码200，实际得到{response.status_code}"
        print("[PASS] 状态码断言通过")

        # 2. 验证响应包含data字段
        assert "data" in response_data, "响应中缺少data字段"
        print("[PASS] data字段断言通过")

        # 3. 验证GraphQL查询结果结构
        assert "findStaffCustByPage" in response_data["data"], "响应中缺少findStaffCustByPage字段"
        print("[PASS] findStaffCustByPage字段断言通过")

        find_staff_cust = response_data["data"]["findStaffCustByPage"]

        # 4. 验证staffCustData数组结构
        assert "staffCustData" in find_staff_cust, "响应中缺少staffCustData字段"
        assert isinstance(find_staff_cust["staffCustData"], list), "staffCustData应该是数组类型"
        print("[PASS] staffCustData数组结构断言通过")

        # 5. 验证分页信息
        assert "pageInfo" in find_staff_cust, "响应中缺少pageInfo字段"
        page_info = find_staff_cust["pageInfo"]

        assert "hasNextPage" in page_info, "pageInfo中缺少hasNextPage字段"
        assert "hasPreviousPage" in page_info, "pageInfo中缺少hasPreviousPage字段"
        assert "totalCount" in page_info, "pageInfo中缺少totalCount字段"

        assert isinstance(page_info["hasNextPage"], bool), "hasNextPage应该是布尔类型"
        assert isinstance(page_info["hasPreviousPage"], bool), "hasPreviousPage应该是布尔类型"
        assert isinstance(page_info["totalCount"], (int, float)), "totalCount应该是数字类型"
        print("[PASS] 分页信息断言通过")

        # 6. 验证数据完整性 - 检查第一条数据的结构
        if len(find_staff_cust["staffCustData"]) > 0:
            first_investor = find_staff_cust["staffCustData"][0]

            # 验证必要字段存在
            required_fields = ["investorId", "investorNam", "mobileNo", "futAssets", "subMonthSum"]
            for field in required_fields:
                assert field in first_investor, f"投资者数据缺少必要字段: {field}"

            # 验证数据类型
            assert isinstance(first_investor["investorId"], str), "investorId应该是字符串类型"
            assert isinstance(first_investor["investorNam"], str), "investorNam应该是字符串类型"
            assert isinstance(first_investor["mobileNo"], str), "mobileNo应该是字符串类型"
            assert isinstance(first_investor["futAssets"], (int, float)), "futAssets应该是数字类型"
            assert isinstance(first_investor["subMonthSum"], (int, float)), "subMonthSum应该是数字类型"

            # 验证标签数据
            if "custLabels" in first_investor:
                assert isinstance(first_investor["custLabels"], list), "custLabels应该是数组类型"
                if len(first_investor["custLabels"]) > 0:
                    first_label = first_investor["custLabels"][0]
                    assert "lableId" in first_label, "标签缺少lableId字段"
                    assert "lableName" in first_label, "标签缺少lableName字段"

            print("[PASS] 数据完整性断言通过")

        # 7. 验证业务逻辑 - 总记录数应该大于0
        assert page_info["totalCount"] > 0, "总记录数应该大于0"
        print("[PASS] 业务逻辑断言通过")

        # 8. 验证数组长度不超过pageSize
        assert len(find_staff_cust["staffCustData"]) <= payload["variables"]["pageSize"], \
            f"返回数据条数不应超过pageSize: {payload['variables']['pageSize']}"
        print("[PASS] 分页大小断言通过")

        print("\n[SUCCESS] 所有断言测试通过！")
        print(f"[DATA] 返回数据统计:")
        print(f"   - 投资者数量: {len(find_staff_cust['staffCustData'])}")
        print(f"   - 总记录数: {page_info['totalCount']}")
        print(f"   - 是否有下一页: {page_info['hasNextPage']}")

        return response_data

    except requests.exceptions.RequestException as e:
        print(f"[FAIL] 请求失败: {e}")
        raise
    except json.JSONDecodeError as e:
        print(f"[FAIL] JSON解析失败: {e}")
        raise
    except AssertionError as e:
        print(f"[FAIL] 断言失败: {e}")
        raise
    except Exception as e:
        print(f"[FAIL] 发生未知错误: {e}")
        raise
pytest.main(["-sv","./run_api.py","--alluredir","./api_result","--clean-alluredir" ])
os.system('allure generate ./api_result -o ./api_report  --clean')
combine_allure("./api_report")